package com.example.scribe;

import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import com.example.scribe.backend.ByteBuddyBackend;

/**
 * A standalone runner that demonstrates compiling and executing Scribe code.
 * Usage:
 * 1. Place your Scribe source code in src/main/resources/demo/
 * 2. Run this class
 * 3. See the compilation and execution results
 */
public class ScribeRunner {
    public static void main(String[] args) throws Exception {
        System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");
        // 从资源目录读取示例
        var cl = ScribeRunner.class.getClassLoader();
        String source;
        // Try comprehensive test file first, then fall back to simple test
        try (var in = cl.getResourceAsStream("demo/while_test_comprehensive.scribe")) {
            if (in != null) {
                source = new String(in.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
            } else {
                try (var in2 = cl.getResourceAsStream("demo/while_test.scribe")) {
                    if (in2 == null) throw new IllegalStateException("Resource not found: demo/while_test.scribe");
                    source = new String(in2.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
                }
            }
        }
        System.out.println("Compiling Scribe source (resource):\n" + source);
        
        // 解析为语法树
        SyntaxNode ast = ParserUtil.parseToSyntax(source);
        System.out.println("\nParsed AST:");
        System.out.println(ast);
        
        // 生成类
        var backend = new ByteBuddyBackend();
        Class<?> generatedClass = backend.generateModuleClass(ast);
        System.out.println("\nGenerated class: " + generatedClass.getName());
        
        // Check if we have test_ functions (comprehensive test mode)
        var testMethods = java.util.Arrays.stream(generatedClass.getDeclaredMethods())
            .filter(m -> m.getName().startsWith("test_") && m.getParameterCount() == 0 && m.getReturnType() == int.class)
            .collect(java.util.stream.Collectors.toList());
        
        if (!testMethods.isEmpty()) {
            // Comprehensive test mode: run all test_ functions
            System.out.println("\n=== While Loop Comprehensive Tests ===");
            System.out.println("Found " + testMethods.size() + " test functions\n");
            
            int passed = 0;
            int failed = 0;
            for (Method testMethod : testMethods) {
                try {
                    System.out.print("Running " + testMethod.getName() + "()... ");
                    Object result = testMethod.invoke(null);
                    System.out.println("Result: " + result + " ✓");
                    passed++;
                } catch (Exception e) {
                    System.out.println("FAILED: " + e.getMessage());
                    if (e.getCause() != null) {
                        System.out.println("  Cause: " + e.getCause().getMessage());
                    }
                    failed++;
                }
            }
            
            System.out.println("\n=== Test Summary ===");
            System.out.println("Passed: " + passed);
            System.out.println("Failed: " + failed);
            System.out.println("Total: " + (passed + failed));
            return;
        }
        
        // Single function mode: find and call one function
        Method toCall = java.util.Arrays.stream(generatedClass.getDeclaredMethods())
            .peek(m -> System.out.println("Found method: " + m))
            .filter(m -> m.getName().equals("main"))
            .findFirst()
            .orElseGet(() -> {
                try { return generatedClass.getDeclaredMethod("while_test"); } catch (NoSuchMethodException e) { 
                    try { return generatedClass.getDeclaredMethod("simple_while"); } catch (NoSuchMethodException e2) {
                        try { return generatedClass.getDeclaredMethod("test"); } catch (NoSuchMethodException e3) { 
                            try { return generatedClass.getDeclaredMethod("var_test"); } catch (NoSuchMethodException e4) { return null; }
                        }
                    }
                }
            });

        if (toCall == null) {
            toCall = java.util.Arrays.stream(generatedClass.getDeclaredMethods())
                .filter(m -> m.getReturnType() == int.class && m.getParameterCount() == 0)
                .findFirst().orElse(null);
        }

        if (toCall == null) {
            toCall = java.util.Arrays.stream(generatedClass.getDeclaredMethods())
                .filter(m -> m.getReturnType() == int.class && m.getParameterCount() == 1 && m.getParameterTypes()[0] == int.class)
                .findFirst().orElse(null);
        }

        if (toCall == null) throw new RuntimeException("No callable function found in generated class");

        System.out.println("\nInvoking: " + toCall);
        Object result;
        if (toCall.getParameterCount() == 0) result = toCall.invoke(null);
        else if (toCall.getParameterCount() == 1) result = toCall.invoke(null, 5);
        else throw new RuntimeException("Demo runner supports up to 1-arg functions only");

        System.out.println("Result: " + result);
    }
}